package com.acmen.easyapi.validation;

import com.acmen.easyapi.annotation.ReqParam;
import com.acmen.easyapi.annotation.RestApi;
import com.acmen.easyapi.model.Response;
import com.acmen.easyapi.util.AnnotationUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.util.List;

/**
 * @author acmen
 * 通过注解切面controller服务
 * @date 2022-07-02
 */
@Aspect
@Order(1)
@Component
public class ValidationAspect {
    @Resource
    private SchemaValidator schemaValidator;
    private static final Logger log = LoggerFactory.getLogger(ValidationAspect.class);

    @Around("@annotation(restApi)")
    public Object around(ProceedingJoinPoint joinPoint, RestApi restApi) throws Throwable {
        Class returnType = ((MethodSignature) joinPoint.getSignature()).getMethod().getReturnType();
        if(!Response.class.isAssignableFrom(returnType)){
            return joinPoint.proceed();
        }
        ReqParam[] reqParams = getReqParams(joinPoint);
        Object[] args = joinPoint.getArgs();
        if (args.length == 0) {
            return joinPoint.proceed();
        }
        Response response = schemaValidator.validate(args, reqParams);
        if (response.isSuccess()) {
            return joinPoint.proceed();
        }
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        log.warn("请求["+request.getServletPath()+"]参数校验不通过,请求参数:{},响应：{}",args,response);
        return response;
    }

    private ReqParam[] getReqParams(ProceedingJoinPoint joinPoint) {
        List<List<Annotation>> parameterAnnotations = AnnotationUtil.getParameterAnnotations(((MethodSignature) joinPoint.getSignature()).getMethod());
        ReqParam[] reqParams = new ReqParam[parameterAnnotations.size()];
        int i = 0;
        for (List<Annotation> annotations : parameterAnnotations) {
            for (Annotation annotation : annotations) {
                if (annotation.annotationType().equals(ReqParam.class)) {
                    reqParams[i] = (ReqParam) annotation;
                }
            }
            i++;
        }
        return reqParams;
    }
}
